(function($) {

    //时时校验
    $.fn.validatebox = function(options) {
        options = options || {};
        var htmlDom = this[0];
        var validateboxOpt = $.data(htmlDom, "validatebox");

        if (validateboxOpt) {
            $.extend(validateboxOpt.options, options);
        } else {
            var t = this;
            validateboxOpt = $.data(htmlDom, "validatebox", {});
        }

        validate(this);
    }

    //form提交时校验
    $.fn.formDispatch = function() {
        if (this.attr("validator")) {
            var htmlDom = this[0];
            var $that = this;
            var nodeType = htmlDom.getAttribute("type");
            if (nodeType != null) {
                //根据元素节点类型不同，采用不同的校验方式
                switch (nodeType.toLowerCase()) {
                    case "text":
                        if (!$that.hasClass('combobox-text')) {
                            _inlineBlur($that);
                        }
                        break;
                    case "password":
                        if (!$that.hasClass('combobox-text')) {
                            _inlineBlur($that);
                        }
                        break;
                    case "checkbox":
                        var $boxDiv = $("#" + $that.attr("name"));
                        _inlineClick($boxDiv);
                        break;
                    case "textarea":
                        _inlineBlur($that);
                        break;
                    case "select-multiple":
                        _inlineSelectMulti($that);
                        break;
                    case "select-one":
                        if ($that.attr("selectType")) {
                            var $comboDiv = $that.parent();
                            var $combovalue = $comboDiv.find(".combobox-value");
                            var $combotext = $comboDiv.find(".combobox-text");
                            _inlineCombobox($combotext, $combovalue, $that.attr("validator"));
                        } else {
                            _inlineHtmlSelectOne($that);
                        }
                        break;
                    default:
                        break;
                }
            }

        }

    }

    /**
     * 根据dom节点的不同，使用不同的校验方法
     * @param $dom
     */
    function validate($dom) {

        if ($dom.attr("validator")) {
            var htmlDom = $dom[0];

            var nodeType = htmlDom.getAttribute("type");
            if (nodeType != null) {
                switch (nodeType.toLowerCase()) {
                    case "text":
                        checkText($dom);
                        break;
                    case "password":
                        checkText($dom);
                        break;
                    case "checkbox":
                        checkCheckbox($dom);
                        break;
                    case "textarea":
                        checkTextarea($dom);
                        break;
                    case "select-multiple":
                        checkSelectMulti($dom);
                        break;
                    case "select-one":
                        checkSelectOne($dom);
                        break;
                }
            }

        }
    }

    /**
     * 对应input节点进行校验
     * @param $dom
     */
    function checkText($dom) {
        var interFunc = null;
        $dom.unbind(".validatebox").bind("focus.validatebox", function() {
            if (interFunc) {
                clearInterval(interFunc);
            }
            interFunc = setInterval(function() {
                _inlineBlur($dom);
            }, 200);
        }).bind("blur.validatebox", function() {
            clearInterval(interFunc);
            interFunc = null;
            removeTip($dom[0]);
        }).bind("mouseover.validatebox", function() {
            if ($dom.hasClass("validatebox-invalid")) {
                _inlineBlur($dom);
            }
        }).bind("mouseout.validatebox", function() {
            removeTip($dom[0]);
        });

    }

    /**
     * 对checkbox组进行校验
     * @param $dom
     */
    function checkCheckbox($dom) {
        var interFunc = null;
        var $boxDiv = $("#" + $dom.attr("name"));
        $.data($boxDiv[0], "validatebox", {});
        $dom.unbind(".validatebox").bind("click.validatebox", function() {
            _inlineClick($boxDiv);
        });

        $boxDiv.unbind(".validatebox").bind("mouseover.validatebox", function() {
            if ($boxDiv.hasClass("validatebox-invalid")) {
                _inlineClick($boxDiv);
            }
        }).bind("mouseout.validatebox", function() {
            var $boxDiv = $("#" + $dom.attr("name"));
            removeTip($boxDiv[0]);
        });
    }

    /**
     * 对textarea进行校验
     * @param $dom
     */
    function checkTextarea($dom) {
        var interFunc = null;
        $dom.unbind(".validatebox").bind("focus.validatebox", function() {
            if (interFunc) {
                clearInterval(interFunc);
            }
            interFunc = setInterval(function() {
                _inlineBlur($dom);
                _addTextAreaMax($dom[0]);
            }, 200);
        }).bind("blur.validatebox", function() {
            clearInterval(interFunc);
            interFunc = null;
            removeTip($dom[0]);
        }).bind("mouseover.validatebox", function() {
            if ($dom.hasClass("validatebox-invalid")) {
                _inlineBlur($dom);
                _addTextAreaMax($dom[0]);
            }
        }).bind("mouseout.validatebox", function() {
            removeTip($dom[0]);
        })
    }

    /**
     * 对多选列表框进行校验
     * @param $dom
     */
    function checkSelectMulti($dom) {
        var interFunc = null;

        if ($dom.parent()[0].nodeName.toLowerCase() != "span") {
            var $span = $("<span></span>");
            $dom.wrap($span);
        }

        $dom.parent().unbind(".validatebox").bind("mouseover.validatebox", function() {
            if ($dom.parent().hasClass("validatebox-invalid")) {
                _inlineSelectMulti($dom);
            }
        }).bind("mouseout.validatebox", function() {
            removeTip($dom[0]);
        })

        $dom.unbind(".validatebox").bind("blur.validatebox", function() {
            removeTip($dom[0]);
        }).bind("change.validatebox", function() {
            _inlineSelectMulti($dom);
        });
    }

    /**
     * 对下拉框进行校验
     * @param $dom
     */
    function checkSelectOne($dom) {

        //自定义的select
        if ($dom.attr("selectType")) {
            var interFunc = null;
            var $comboDiv = $dom.parent();
            var $combovalue = $comboDiv.find(".combobox-value");
            var $combotext = $comboDiv.find(".combobox-text");
            $combotext.unbind(".validatebox").bind("mouseover.validatebox", function() {
                if ($combotext.hasClass("validatebox-invalid")) {
                    _inlineCombobox($combotext, $combovalue, $dom.attr("validator"));
                }
            }).bind("mouseout.validatebox", function() {
                removeTip($combotext[0]);
            });

            //事件需要绑定在那些数据项上面
            var $comboxContentDiv = $('#combobox-content-'+$dom.parent().attr('id'));
            var $comboxItems = $comboxContentDiv.find(".combobox-item");

            $comboxItems.each(function() {
                var $that = $(this);
                $that.unbind(".validatebox").bind("click.validatebox", function() {
                    if ($that.hasClass("combobox-item-selected")) {
                        _inlineCombobox($combotext, $combovalue, $dom.attr("validator"));
                        $combotext.trigger('mouseout');
                    }
                })
            });
        }
        //html原生的select
        else {
            if ($dom.parent()[0].nodeName.toLowerCase() != "span") {
                var $span = $("<span></span>");
                $dom.wrap($span);
            }

            $dom.parent().unbind(".validatebox").bind("mouseover.validatebox", function() {
                if ($dom.parent().hasClass("validatebox-invalid")) {
                    _inlineHtmlSelectOne($dom);
                }
            }).bind("mouseout.validatebox", function() {
                removeTip($dom[0]);
            });

            $dom.unbind(".validatebox").bind("change.validatebox", function() {
                _inlineHtmlSelectOne($dom);
            }).bind("blur.validatebox", function() {
                removeTip($dom[0]);
            })
        }

    }

    //实时验证：blur验证
    function _inlineBlur($field) {
        var value = $field.attr("value");
        var validators = $field.attr("validator");
        var pattern = /\W+/;
        var rules = validators.split(pattern);
        var flg = true;
        for (i = 0; i < rules.length; i++) {
            switch (rules[i]) {
                case "required":
                    if (!value || jQuery.trim(value) == "") {
                        flg = false;
                        $field.addClass("validatebox-invalid");
                        addTip($field[0], allRules[rules[i]].alertText);
                    }
                    break;
                case "length":
                    //
                    if (value && jQuery.trim(value) != "") {
                        if ((value.length < parseInt(rules[i + 1])) || (value.length > parseInt(rules[i + 2]))) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2 + rules[i + 2] + allRules[rules[i]].alertText3);
                        }
                    } else {
                        if (rules[i + 1] > 0) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2 + rules[i + 2] + allRules[rules[i]].alertText3);
                        }
                    }
                    break;
                case "telephone":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "mobilephone":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "email":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "date":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "ip":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "chinese":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "url":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "zipcode":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "idCard":
                    if (value && jQuery.trim(value) != "") {
                        var msg = isIdCard(value)
                        if (msg) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], msg);
                        }
                    }
                    break;
                case "onlyNumber":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "integer":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "positiveInteger":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "negativeInteger":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "nonPositiveInteger":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "nonNegativeInteger":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "decimalNum":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "onlyLetter":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "noSpecialCaracters":
                    if (value && jQuery.trim(value) != "") {
                        if (!eval(allRules[rules[i]].regex).test(value)) {
                            flg = false;
                            $field.addClass("validatebox-invalid");
                            addTip($field[0], allRules[rules[i]].alertText);
                        }
                    }
                    break;
                case "minSelected":
                    var min = parseInt(rules[i + 1]);
                    if ($field.find("option[selected]").not("[value='']").length < min) {
                        flg = false;
                        $field.addClass("validatebox-invalid");
                        addTip($field[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                    }
                    break;
                case "maxSelected":
                    var max = parseInt(rules[i + 1]);
                    if ($field.find("option[selected]").not("[value='']").length > max) {
                        flg = false;
                        $field.addClass("validatebox-invalid");
                        addTip($field[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                    }
                    break;

                default :
                    if (parseInt(rules[i]) != "NaN") {
                        try {
                            //自定义检查：函数名即为规则名
                            var rt = window[rules[i]]();
                            if (rt != "true") {
                                flg = false;
                                $field.addClass("validatebox-invalid");
                                addTip($field[0], rt);
                            }
                        } catch(err) {

                        }
                    }
                    break;
            }
            if (!flg) {
                break;
            }
        }
        if (flg) {
            $field.removeClass('validatebox-invalid');
        }
        return flg;
    }

    //实时验证：click checkbox验证
    function _inlineClick($boxDiv) {
        var validators = $boxDiv.attr("validator");
        var pattern = /\W+/;
        var rules = validators.split(pattern);
        var flg = true;
        for (i = 0; i < rules.length; i++) {
            switch (rules[i]) {
                case "required":
                    var min = 1;
                    var groupname = $boxDiv.attr("groupname");
                    var $boxs = $boxDiv.find(":checkbox[name=" + groupname + "][checked],:radio[name=" + groupname + "][checked]");
                    if ($boxs.length < min) {
                        flg = false;
                        $boxDiv.addClass("validatebox-invalid");
                        addTip($boxDiv[0], allRules[rules[i]].alertText);
                        //                        _addGroupMsg($vsForm, fieldnum, $boxDiv, allRules[rules[i]].alertText);
                    }
                    break;
                case "minSelected":
                    var min = parseInt(rules[i + 1]);
                    var groupname = $boxDiv.attr("groupname");
                    var $boxs = $boxDiv.find(":checkbox[name=" + groupname + "][checked],:radio[name=" + groupname + "][checked]")
                    if ($boxs.length < min) {
                        flg = false;
                        $boxDiv.addClass("validatebox-invalid");
                        addTip($boxDiv[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                    }
                    break;
                case "maxSelected":
                    var max = parseInt(rules[i + 1]);
                    var groupname = $boxDiv.attr("groupname");
                    var $boxs = $boxDiv.find(":checkbox[name=" + groupname + "][checked],:radio[name=" + groupname + "][checked]")
                    if ($boxs.length > max) {
                        flg = false;
                        $boxDiv.addClass("validatebox-invalid");
                        addTip($boxDiv[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                        //                        _addGroupMsg($vsForm, fieldnum, $boxDiv, allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                    }
                    break;
                default :break;
            }
            if (!flg) {
                break;
            }
        }
        if (flg) {
            $boxDiv.removeClass('validatebox-invalid');
            removeTip($boxDiv[0]);
        }
        return flg;
    }

    //实时验证 html下拉框
    function _inlineHtmlSelectOne($select) {
        var validators = $select.attr("validator");
        var pattern = /\W+/;
        var rules = validators.split(pattern);
        var flg = true;
        for (i = 0; i < rules.length; i++) {
            switch (rules[i]) {
                case "required":
                    if ($select.val() == "") {
                        flg = false;
                        $select.parent().addClass("validatebox-invalid");
                        addTip($select[0], allRules[rules[i]].alertText);

                    }
                    break;
            }
        }
        if (flg) {
            $select.parent().removeClass("validatebox-invalid");
        }
        return flg;
    }

    //实时验证 自定义下拉框
    function _inlineCombobox($combotext, $combovalue, vtype) {
        var pattern = /\W+/;
        var rules = vtype.split(pattern);
        var flg = true;

        for (i = 0; i < rules.length; i++) {
            switch (rules[i]) {
                case "required":
                    if ($combovalue.val() == "") {
                        flg = false;
                        $combotext.addClass("validatebox-invalid");
                        addTip($combotext[0], allRules[rules[i]].alertText);
                    }
                    break;
            }
        }
        if (flg) {
            $combotext.removeClass("validatebox-invalid");
        }

        return flg;
    }

    //实时验证：click select验证
    function _inlineSelectMulti($boxDiv) {
        var validators = $boxDiv.attr("validator");
        var pattern = /\W+/;
        var rules = validators.split(pattern);
        var flg = true;
        for (i = 0; i < rules.length; i++) {
            switch (rules[i]) {
                case "required":
                    var min = 1;
                    var $selected = $boxDiv.find(":selected");
                    if ($selected.length < min) {
                        flg = false;
                        $boxDiv.parent().addClass("validatebox-invalid");
                        addTip($boxDiv[0], allRules[rules[i]].alertText);
                        //                        _addGroupMsg($vsForm, fieldnum, $boxDiv, allRules[rules[i]].alertText);
                    }
                    break;
                case "minSelected":
                    var min = parseInt(rules[i + 1]);
                    var $selected = $boxDiv.find(":selected");
                    if ($selected.length < min) {
                        flg = false;
                        $boxDiv.parent().addClass("validatebox-invalid");
                        addTip($boxDiv[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                        //                        _addGroupMsg($vsForm, fieldnum, $boxDiv, allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                    }
                    break;
                case "maxSelected":
                    var max = parseInt(rules[i + 1]);
                    var $selected = $boxDiv.find(":selected");
                    if ($selected.length > max) {
                        flg = false;
                        $boxDiv.parent().addClass("validatebox-invalid");
                        addTip($boxDiv[0], allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                        //                        _addGroupMsg($vsForm, fieldnum, $boxDiv, allRules[rules[i]].alertText + rules[i + 1] + allRules[rules[i]].alertText2);
                    }
                    break;
                default :break;
            }
            if (!flg) {
                break;
            }
        }
        if (flg) {
            $boxDiv.parent().removeClass('validatebox-invalid');
        }
        return flg;
    }

    //自动截取限定textarea 长度
    function _addTextAreaMax(obj) {
        var $field = jQuery(obj)
        var value = $field.attr("value");
        var validators = $field.attr("validator");
        var pattern = /\W+/;
        var rules = validators.split(pattern);
        var maxLen = 0;
        for (i = 0; i < rules.length; i++) {
            if (rules[i] == "length") {
                maxLen = rules[i + 2];
                break;
            }
        }
        if (parseInt(maxLen) > 0) {
            var len = value.length;
            if (len > parseInt(maxLen)) {
                $field.val(value.substr(0, maxLen))
            }
        }
    }

    /**
     * 给某一节点添加错误提示
     * @param htmlDom
     * @param errorMess
     */
    function addTip(htmlDom, errorMess) {
        if (typeof $.data(htmlDom, "validatebox") == 'undefined') {
            $.data(htmlDom, "validatebox", {});
        }
        var _e = $(htmlDom);
        //        var _f = $.data(htmlDom, "validatebox").message;
        var tip = $.data(htmlDom, "validatebox").tip;

        if (!tip) {
            tip = $("<div class=\"validatebox-tip\">" + "<span class=\"validatebox-tip-content\">" + errorMess + "</span>" + "<span class=\"validatebox-tip-pointer\">" + "</span>" + "</div>").appendTo("body");
            $.data(htmlDom, "validatebox").tip = tip;
        }
        //        tip.find(".validatebox-tip-content").html(_f);
        //tip.css({display:"block",left:_e.offset().left + _e.outerWidth(),top:_e.offset().top});
		tip.css({display:"block",left:_e.offset().left + 20,top:_e.offset().top+10});
    }

    //删除错误提示
    function removeTip(htmlDom) {
        if (typeof $.data(htmlDom, "validatebox") == 'undefined') {
            $.data(htmlDom, "validatebox", {});
        }
        var tip = $.data(htmlDom, "validatebox").tip;
        if (tip) {
            tip.remove();
            $.data(htmlDom, "validatebox").tip = null;
        }
    }
})(jQuery)